# BSD3.0
# cili@163.com

import tkinter as tk
from tkinter import ttk
import numpy as np



patterns = [
        [[0, 0, 1, 1, 1],[0, 1, 0, 0, 1],[1, 0, 0, 0, 1]],
        [[1, 1, 1, 1, 1],[1, 0, 0, 0, 1],[1, 1, 1, 1, 1]],
        [[1, 1, 1, 1, 1],[1, 1, 1, 1, 1]]
]

class GameOfLife(tk.Tk):
    def __init__(self,size,index):
        super().__init__()
        self.title("生命游戏")
        self.size = size
        self.matrix = np.zeros(self.size, dtype=int)
        self.pattern_index = index
        self.init_matrix_value(patterns[self.pattern_index])
        self.top_panel = tk.Frame(self)
        self.top_panel.pack()

        self.round_label = ttk.Label(self.top_panel, text="当前轮数：0")
        self.round_label.grid(row=0, column=0)
        self.live_cells_label = ttk.Label(self.top_panel, text="存活元素：0")
        self.live_cells_label.grid(row=0, column=1)
        self.current_round=0

        self.canvas = tk.Canvas(self, width=500, height=500)
        self.canvas.pack()
        self.draw_matrix()
        self.update_idletasks()
        self.canvas.bind("<Button-1>", self.update_matrix)

        self.bottom_panel = tk.Frame(self)
        self.bottom_panel.pack()
        self.initialize_button = ttk.Button(self.bottom_panel, text="重置数据", command=self.docmd)
        self.initialize_button.pack(side="left",padx=5)
        self.initialize_button = ttk.Button(self.bottom_panel, text="更换模式", command=self.change_pattern)
        self.initialize_button.pack(side="left", padx=5)
        self.evolve_one_button = ttk.Button(self.bottom_panel, text="演化1轮", command=self.evolve_one_round)
        self.evolve_one_button.pack(side="left",padx=5)
        self.auto_button_flag = True
        self.auto_flag = False
        self.evolve_ten_button = ttk.Button(self.bottom_panel, text="自动演化", command=self.evolve_ten_rounds)
        self.evolve_ten_button.pack(side="left",padx=5)

    def change_pattern(self):
        self.pattern_index = self.pattern_index+1
        if self.pattern_index>len(patterns)-1:self.pattern_index=0
        pattern = patterns[self.pattern_index]
        self.init_matrix_value(pattern)
        self.draw_matrix()

    def init_matrix_value(self,pattern):
        self.matrix[:] = 0
        rotated_pattern = [list(row) for row in zip(*pattern)]
        pw = len(pattern[0])
        ph = len(pattern)
        sx = self.size[0]//2-pw//2
        sy = self.size[1]//2-ph//2
        self.matrix[sx:sx + pw, sy:sy + ph] = rotated_pattern

    def update_matrix(self, event):
        w, h = self.matrix.shape
        rect_width = self.canvas.winfo_width() / w
        rect_height = self.canvas.winfo_height() / h
        x, y = int(event.x // rect_width), int(event.y // rect_height)
        self.matrix[x, y] = 1 if self.matrix[x, y] == 0 else 0
        self.draw_matrix()

    def draw_matrix(self):
        self.canvas.delete("all")
        w, h = self.matrix.shape
        rect_width = self.canvas.winfo_reqwidth() / w
        rect_height = self.canvas.winfo_reqheight() / h
        for i in range(w):
            for j in range(h):
                x0, y0 = i * rect_width, j * rect_height
                x1, y1 = (i + 1) * rect_width, (j + 1) * rect_height
                if self.matrix[i, j] == 1:
                    self.canvas.create_rectangle(x0, y0, x1, y1, fill="green", outline="")
                else:
                    self.canvas.create_rectangle(x0, y0, x1, y1, fill="white", outline="")
        self.round_label.config(text="当前轮数：" + str(self.current_round))
        self.live_cells_label.config(text=f"存活元素：{np.sum(self.matrix)}")

    def docmd(self):
        self.matrix = np.zeros(self.size, dtype=int)
        self.init_matrix_value(patterns[self.pattern_index])
        self.draw_matrix()
        self.current_round=0

    def evolve_one_round(self):
        w, h = self.matrix.shape
        temp_matrix = np.zeros((w, h), dtype=int)
        for x in range(w):
            for y in range(h):
                xs, xe = max(0, x - 1), min(w - 1, x + 1)
                ys, ye = max(0, y - 1), min(h - 1, y + 1)
                sub_m = self.matrix[xs:xe + 1, ys:ye + 1]
                entity = self.matrix[x, y]
                neighbors = np.sum(sub_m) - entity
                if entity == 1:
                    temp_matrix[x, y] = 1 if neighbors in [2,3] else 0
                else:
                    temp_matrix[x, y] = 1 if neighbors == 3 else 0
        self.matrix = temp_matrix
        self.current_round = self.current_round + 1
        self.draw_matrix()

    def evolve_ten_rounds(self):
        if self.auto_button_flag:
            self.evolve_one_button.config(state="disable")
            self.initialize_button.config(state="disable")
            self.evolve_ten_button.config(text="停止演化")
            self.auto_flag=True
            self.auto_button_flag=False
            while self.auto_flag:
                self.evolve_one_round()
                self.update()
                self.after(500)  # 每一轮的结果呈现2秒
        else:
            self.auto_flag=False
            self.evolve_one_button.config(state="normal")
            self.initialize_button.config(state="normal")
            self.auto_button_flag = True
            self.evolve_ten_button.config(text="自动演化")

if __name__ == "__main__":
    app = GameOfLife((51,51),0)
    app.mainloop()